<?php

require_once("evalable.php");
require_once("listobject.php");

class LambdaObject extends Evalable {

    var $bindings = null;
    var $code = null;
    var $env = null;

    function LambdaObject($bindings, $code, $env) {
        $this->bindings = $bindings;
        $this->code = $code;
        $this->env = $env;
    }

    function lispeval($env, $args = null) {
        $lisper = $env->get('*this*');

        if ($this->env) {
            $lisper->push_e($this->env->e);
        } else {
            $lisper->push_e();
        }

        $i = 0;
        $n = $this->bindings->count();
        while ($i < $n) {
            if ($this->bindings->getitem($i)->n == "&rest") {
                $rest = array();
                foreach (array_slice($args, 1) as $arg) {
                    $rest[] = $arg->lispeval($lisper->e);
                }
                $lisper->lexical_intern(
                        $this->bindings->getitem($i + 1)->n,
                        new ListObject($rest)
                );
                $i = $i + 1;
            } else {
                $lisper->lexical_intern(
                        $this->bindings->getitem($i)->n,
                        $args[$i]->lispeval($lisper->e)
                );
            }
            $i = $i + 1;
        }
        $ans = new LogicObject(0.0);

        foreach ($this->code as $code) {
            $ans = $code->lispeval($lisper->e);
        }
        $lisper->pop_e();
        return $ans;
    }

    function repr() {
        if (count($this->code) == 1) {
            if (is_object($this->code[0]))
                $str = $this->code[0]->repr();
            else
                $str = $this->code[0];
            return "(lambda " . $this->bindings->repr() . " " . $str . ")";
        }
        else {

            $ls = new ListObject(array_merge(array('begin'), $this->code));
            $ls = $ls->repr();
            return "(lambda " . $this->bindings->repr() . " " . $ls . ")";
        }
    }

    function nullp() {
        return new LogicObject(0);
    }

}